﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Web;

namespace SignalRApp.Repository
{
    public class Repository<TEntity> where TEntity : class
    {
        private SignalRAppContext context;
        private DbSet<TEntity> dbSet;

        public Repository(SignalRAppContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public IUnitOfWork UnitOfWork
        {
            get
            {
                return context;
            }
        }

        public virtual IEnumerable<TEntity> Get(
          Expression<Func<TEntity, bool>> filter = null,
          Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
          string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetById(object id)
        {
            return dbSet.Find(id);
        }

        public virtual void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }

        public virtual void Delete(object id)
        {
            TEntity entityForDelete = dbSet.Find(id);
            Delete(entityForDelete);
        }

        public virtual void Delete(TEntity entityForDelete)
        {
            if (context.Entry(entityForDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityForDelete);
            }
            dbSet.Remove(entityForDelete);
        }

        public virtual void Update(TEntity entityForUpdate)
        {
            RemoveHoldingEntityInContext(entityForUpdate);
            dbSet.Attach(entityForUpdate);
            context.Entry(entityForUpdate).State = EntityState.Modified;
        }

        /// <summary>
        /// 用于解决更新失败的问题，在Context中还保留有当前实体的副本所致，这里只要我们将实体副本从内存中完全移除，就可以了。
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private Boolean RemoveHoldingEntityInContext(TEntity entity)
        {
            var objContext = ((IObjectContextAdapter)context).ObjectContext;
            var objSet = objContext.CreateObjectSet<TEntity>();
            var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);

            Object foundEntity;
            var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);

            if (exists)
            {
                objContext.Detach(foundEntity);
            }
            return (exists);
        }
    }
}